#include "RingQueue.hpp"  // 引入环形队列头文件
#include <string>
#include <unistd.h>  // 引入 POSIX 的 sleep 函数

// 常量定义，设置生产者和消费者线程的数量
const int CON_NUM = 3, PRO_NUM = 3;
Mutex print_lock;  // 用于保护打印操作的互斥锁

// 定义一个结构体，用于存储线程的相关数据
struct thread_data
{
    thread_data(RingQueue<int>* rq = nullptr, std::string name = "", int i = 0)
        :_rq(rq)
        ,_name(name)
    {
        _name += " thread-" + std::to_string(i);  // 线程名称，带上索引以区分不同的线程
    }
    
    RingQueue<int>* _rq;  // 环形队列的指针
    std::string _name;    // 线程的名称
};

// 消费者线程的函数
void* con_func(void* args)
{
    thread_data* td = static_cast<thread_data*> (args);  // 将传入的参数转换为 thread_data 指针
    while(1)  // 无限循环，消费者持续消费
    {
        int data = 0;
        td->_rq->Pop(&data);  // 从环形队列中取出数据

        // 锁住打印操作，保证输出不会被多个线程干扰
        {
            LockGuard guard(print_lock);
            std::cout << td->_name << " consume data: " << data << std::endl;  // 打印消费的数据
        }
        sleep(1);  // 模拟消费延时
    }
}

// 生产者线程的函数
void* pro_func(void* args)
{
    thread_data* td = static_cast<thread_data*> (args);  // 将传入的参数转换为 thread_data 指针
    while(1)  // 无限循环，生产者持续生产
    {
        int data = rand() % 1000;  // 生成一个随机数据，模拟生产的任务数据
        td->_rq->Equeue(data);  // 向环形队列中插入数据

        // 锁住打印操作，保证输出不会被多个线程干扰
        {
            LockGuard guard(print_lock);
            std::cout << td->_name << " produce a data: " << data << std::endl;  // 打印生产的数据
        }
        // sleep(1);  // 如果需要模拟生产者操作的延时，可以解除注释
    }
}

int main()
{
    std::vector<pthread_t> con, pro;  // 存储消费者和生产者线程的 ID
    RingQueue<int>* rq = new RingQueue<int>();  // 创建一个环形队列对象，用于生产者和消费者之间的数据交换

    // 创建消费者线程
    for(int i = 0; i < CON_NUM; i++)
    {
        thread_data* td = new thread_data(rq, "consumer", i);  // 创建线程数据对象
        pthread_t tid;
        pthread_create(&tid, nullptr, con_func, td);  // 创建消费者线程
        con.push_back(tid);  // 将线程 ID 存入列表
    }

    // 创建生产者线程
    for(int i = 0; i < PRO_NUM; i++)
    {
        thread_data* td = new thread_data(rq, "producer", i);  // 创建线程数据对象
        pthread_t tid;
        pthread_create(&tid, nullptr, pro_func, td);  // 创建生产者线程
        pro.push_back(tid);  // 将线程 ID 存入列表
    }

    // 等待所有消费者线程结束
    for(auto& tid : con) pthread_join(tid, nullptr);

    // 等待所有生产者线程结束
    for(auto& tid : pro) pthread_join(tid, nullptr);

    return 0;  // 程序结束
}
